package com.shelpe.services.sinbad.controller.sinbad;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.shelpe.services.sinbad.controller.LogDto;
import com.shelpe.services.sinbad.controller.LogDto.LogNoteable;
import com.shelpe.services.sinbad.entity.jpa.Message;
import com.shelpe.services.sinbad.entity.jpa.MessageTopics;
import com.shelpe.services.sinbad.entity.jpa.MessageTopics.DialogStatus;
import com.shelpe.services.sinbad.entity.jpa.MessageTopics.FlagForm;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.repository.jpa.MessageRepository;
import com.shelpe.services.sinbad.repository.jpa.MessageTopicsRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@RestController
@RequestMapping(value = "/sinbadservice")
@Api("v2消息中心相关的API")
@Slf4j
public class Message2Controller {
	public final static Predicate[] TEMPLATE = new Predicate[0];
	@Autowired
	private MessageRepository messageRepository;
	@Autowired
	private MessageTopicsRepository messageTopicsRepository;
	@Autowired
	private UserRepository userRepository;

	@ApiOperation(value = "用户消息并分发给用户")
	@RequestMapping(path = "/messages", method = RequestMethod.POST)
	public MessageDto createInformation(@RequestBody MessageDto dto) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		MessageTopics mess = new MessageTopics();
		BeanUtils.copyProperties(dto, mess);
		if (StringUtils.isNotBlank(dto.getIsDialog())) {
			mess.setIsDialog(DialogStatus.from(dto.getIsDialog()));
		}
		if (StringUtils.isNotBlank(dto.getFlagForm())) {
			mess.setFlagForm(FlagForm.from(dto.getFlagForm()));
		}
		if (StringUtils.isBlank(dto.getType())) {
			mess.setType("user");
		}
		mess.setCreateTime(new Date());
		this.messageTopicsRepository.save(mess);
		log.debug("finish create createInformation:{}", mess);
		dto.setInformID(mess.getMessageID());
		dto.setTopicsID(mess.getMessageID());
		dto.setCreateTime(sdf.format(mess.getCreateTime()));
		if (mess.getIsDialog() == null) {
			dto.setIsDialog(DialogStatus.notDialog.name());
		} else {
			dto.setIsDialog(mess.getIsDialog().name());
		}
		if (mess.getFlagForm() == null) {
			dto.setFlagForm(FlagForm.envelope.name());
		} else {
			dto.setFlagForm(mess.getFlagForm().getValue());
		}
		/** 分发给各个用户阶段 */
		this.messageRepository.deliver2messages(dto.getTitle(), dto.getContent(), mess.getType(),
				dto.getFlagForm() + "_" + dto.getIsDialog(), dto.getTopicsID(), mess.getCreateTime());

		return dto;
	}

	@ApiOperation(value = "删除不基于用户消息并且删除分发出去的消息")
	@RequestMapping(path = "/messages", method = RequestMethod.DELETE)
	@ResponseBody
	public List<MessageDto> delInformation(
			@RequestParam(name = "inform_id", defaultValue = "0", required = false) long informID) {
		List<MessageDto> dtos = new ArrayList<MessageDto>();
		if (informID > 0) {
			/** 删除的message_topics表数据 */
			MessageTopics topics = this.messageTopicsRepository.findByMessageID(informID);
			if (topics != null) {
				MessageDto dto = new MessageDto();
				BeanUtils.copyProperties(topics, dto);
				dto.setFlagForm(topics.getFlagForm().getValue());
				dto.setIsDialog(topics.getIsDialog().name());
				dto.setTopicsID(topics.getMessageID());
				this.messageTopicsRepository.delete(topics);
				dtos.add(dto);
			}
			/** 删除的user_message_delivery表数据 */
			this.messageRepository.deleteByTopicsID(informID);
		}
		return dtos;
	}

	@ApiOperation(value = "查看不基于用户所有消息")
	@RequestMapping(path = "/messages", method = RequestMethod.GET)
	public List<MessageDto> findInformation() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		List<MessageDto> dtos = new ArrayList<MessageDto>();
		List<MessageTopics> messes = (List<MessageTopics>) this.messageTopicsRepository.findAll();
		if (messes != null && messes.size() > 0) {
			for (MessageTopics mess : messes) {
				MessageDto dto = new MessageDto();
				dto.setTopicsID(mess.getMessageID());
				dto.setContent(mess.getContent());
				dto.setFlagForm(mess.getFlagForm().name());
				dto.setIsDialog(mess.getIsDialog().name());
				dto.setTitle(mess.getTitle());
				dto.setCreateTime(sdf.format(mess.getCreateTime()));

				dtos.add(dto);
			}
		}

		return dtos;
	}

	@ApiOperation(value = "查看不基于/基于用户的所有消息并分页")
	@RequestMapping(method = RequestMethod.GET, path = "/messages/actions")
	public Page<LogDto<LogDto.LogNoteable>> findInformation(
			@RequestParam(name = "user_id", defaultValue = "0") long userID,
			@RequestParam(name = "type", defaultValue = "user") String type,
			@RequestParam(name = "page_num", defaultValue = "0") int page,
			@RequestParam(name = "page_size", defaultValue = "20") int size) {
		PageRequest pr = new PageRequest(page, size);
		Date today = DateUtils.truncate(new Date(), Calendar.DATE);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Page<LogDto<LogDto.LogNoteable>> dtos = null;

		List<LogDto<LogDto.LogNoteable>> list = new ArrayList<LogDto<LogDto.LogNoteable>>();
		if (userID != 0) {
			Page<Message> messes = this.messageRepository.findByTypeAndUserIDAndCreateTimeBeforeOrderByCreateTimeDesc(
					type, userID, DateUtils.addDays(today, +1), pr);
			for (Message mess : messes) {
				LogDto<LogNoteable> dto = new LogDto<LogNoteable>();
				BeanUtils.copyProperties(mess, dto);
				dto.setName(mess.getTitle());
				dto.setCreateTime(sdf.format(mess.getCreateTime()));
				if (StringUtils.isNotBlank(mess.getSubType())) {
					String[] arr = mess.getSubType().split("_");
					dto.setFlagForm(arr[0]);
					dto.setIsDialog(arr[1]);
				}
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, messes.getTotalElements());
		} else {
			Page<MessageTopics> messes = this.messageTopicsRepository
					.findByCreateTimeBeforeOrderByCreateTimeDesc(DateUtils.addDays(today, +1), pr);
			for (MessageTopics mess : messes) {
				LogDto<LogNoteable> dto = new LogDto<LogNoteable>();
				dto.setName(mess.getTitle());
				dto.setInformID(mess.getMessageID());
				dto.setCreateTime(sdf.format(mess.getCreateTime()));
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, messes.getTotalElements());
		}

		return dtos;
	}

	/**
	 * 创建基于用户信息
	 * 
	 * @param userID
	 * @param dto
	 * @return
	 */
	@ApiOperation(value = "创建基于用户消息")
	@RequestMapping(path = "/users/{user_id}/messages", method = RequestMethod.POST)
	public MessageDto createUserMessage(@PathVariable("user_id") long userID, @RequestBody MessageDto dto) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		User user = this.userRepository.findOne(userID);
		Assert.notNull(userID, "user_not_found");
		Message mess = new Message();
		BeanUtils.copyProperties(dto, mess);
		mess.setUserID(userID);
		mess.setNick(user.getNick());
		if (StringUtils.isBlank(dto.getCreateTime())) {
			mess.setCreateTime(new Date());
		} else {
			try {
				mess.setCreateTime(sdf.parse(dto.getCreateTime()));
			} catch (ParseException e) {
				mess.setCreateTime(new Date());
				log.error("JsonProcessingException:{}", e);
			}
		}
		mess.setLastModifeTime(new Date());
		mess.setUnread(0);
		this.messageRepository.save(mess);
		log.debug("finish create message:{}", mess);
		dto.setInformID(mess.getInformID());

		return dto;
	}

	/**
	 * 修改基于用户的信息
	 * 
	 * @param userID
	 * @param messageID
	 */
	@ApiOperation(value = "修改基于用户某个未读消息的状态")
	@RequestMapping(path = "/users/{user_id}/messages/{message_id}/@read", method = RequestMethod.PUT)
	public MessageDto updateMessage(@PathVariable("user_id") long userID, @PathVariable("message_id") long messageID) {
		Message mess = this.messageRepository.findOne(messageID);
		Assert.notNull(mess, "mess_not_foud");
		MessageDto dto = new MessageDto();
		log.debug("updateMessage: {}", messageID);
		mess.setUnread(1);
		mess.setLastModifeTime(new Date());
		this.messageRepository.save(mess);
		dto.setUnread(mess.getUnread());

		return dto;
	}

	/**
	 * 查看所有信息
	 * 
	 * @param userID
	 * @param containerID
	 * @param unread
	 * @return
	 */
	@ApiOperation(value = "查看用户的某类型消息")
	@RequestMapping(path = "/users/{user_id}/messages", method = RequestMethod.GET)
	public List<MessageDto> findUserMessage(@PathVariable("user_id") long userID,
			@RequestParam(name = "container_id", defaultValue = "0", required = false) long containerID,
			@RequestParam(required = false, defaultValue = "0") int unread,
			@RequestParam(name = "type", required = false, defaultValue = "message") String type) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date today = DateUtils.truncate(new Date(), Calendar.DATE);
		List<MessageDto> dtos = new ArrayList<MessageDto>();
		List<Message> messes = null;
		if (type.equals("news")) {
			messes = this.messageRepository.findByUserIDAndTypeAndCreateTimeBeforeOrderByCreateTimeDesc(userID, "user",
					DateUtils.addDays(today, +1));
		} else {
			messes = this.messageRepository.findByUserIDAndContainerIDAndUnread(userID, containerID, unread);
		}
		if (messes != null && messes.size() > 0) {
			for (Message mess : messes) {
				MessageDto dto = new MessageDto();
				BeanUtils.copyProperties(mess, dto);
				dto.setCreateTime(sdf.format(mess.getCreateTime()));
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@ApiOperation(value = "创建不基于用户消息")
	@RequestMapping(path = "/messages/@out_user", method = RequestMethod.POST)
	public MessageDto createMessage(@RequestBody MessageDto dto) {
		Message mess = dto.to();
		mess.setUserID(0);
		mess.setCreateTime(new Date());
		mess.setLastModifeTime(new Date());
		mess.setContainerID(0);
		mess.setType("");
		mess.setUnread(0);
		this.messageRepository.save(mess);

		MessageDto resDto = new MessageDto();
		resDto.from(mess);
		dto.setInformID(mess.getInformID());

		return resDto;
	}

	@ApiOperation(value = "查看消息")
	@RequestMapping(path = "/messages/@query", method = RequestMethod.GET)
	public List<MessageDto> findMessage(
			@RequestParam(name = "user_id", defaultValue = "0", required = false) final long userID,
			@RequestParam(name = "message_type", required = false, defaultValue = "message") String messageType) {
		List<Message> pos = null;
		if ("ad".equals(messageType)) {
			pos = this.messageRepository.findTop3ByMessageTypeOrderByCreateTimeDesc(messageType);
		} else {
			pos = this.messageRepository.findAll(new Specification<Message>() {
				@Override
				public Predicate toPredicate(Root<Message> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
					List<Predicate> predicates = new ArrayList<Predicate>();
					predicates.add(cb.equal(root.get("messageType"), messageType));
					if (userID > 0) {
						predicates.add(cb.equal(root.get("userID"), userID));
					}
					return cb.and(predicates.toArray(TEMPLATE));
				}
			});
		}

		List<MessageDto> dtos = new ArrayList<MessageDto>();
		if (pos != null && pos.size() > 0) {
			for (Message po : pos) {
				MessageDto dto = new MessageDto();
				dto.from(po);
				dto.setCreateTime(DateFormatUtils.format(po.getCreateTime(), "yyyy-MM-dd"));
				dtos.add(dto);
			}
		}
		return dtos;
	}

	/**
	 * 查看单个消息
	 * 
	 * type:默认：user 后台：background
	 * 
	 * @param userID
	 * @param messageID
	 * @return
	 * 
	 */
	@ApiOperation(value = "查看单个消息")
	@RequestMapping(path = "/messages/{message_id}", method = RequestMethod.GET)
	public MessageDto findMessageOne(@PathVariable("message_id") long messageID,
			@RequestParam(name = "type", defaultValue = "user") String type) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		MessageDto dto = new MessageDto();
		if (type.equals("user")) {
			Message mess = this.messageRepository.findOne(messageID);
			Assert.notNull(mess, "mess_not_foud");
			BeanUtils.copyProperties(mess, dto);
			dto.setCreateTime(sdf.format(mess.getCreateTime()));
		} else {
			MessageTopics topic = this.messageTopicsRepository.findOne(messageID);
			Assert.notNull(topic, "mess_not_foud");
			BeanUtils.copyProperties(topic, dto);
			dto.setCreateTime(sdf.format(topic.getCreateTime()));
		}

		return dto;
	}

	@Data
	@JsonInclude(Include.NON_DEFAULT)
	public static class MessageDto {
		@JsonProperty("inform_id")
		private long informID = -1;
		@JsonProperty("user_id")
		private long userID = -1;
		private String nick;
		@JsonProperty("container_id")
		private long containerID = -1;
		@JsonProperty("content_type")
		private String type;
		@JsonProperty("content")
		private String content;
		@JsonProperty("create_time")
		@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
		private String createTime;
		@JsonProperty("read")
		private int unread = -1;
		@JsonProperty("container_url")
		private String containerUrl;

		@JsonProperty("flag_form")
		private String flagForm;// 消息标签形式
		@JsonProperty("is_dialog")
		private String isDialog;// 是否弹窗;1:弹窗 0:不弹窗(默认)
		private String title; // 消息标题
		@JsonProperty("topics_id")
		private long topicsID = -1;
		@JsonProperty("sub_type")
		private String subType;
		@JsonProperty("message_type")
		private String messageType = "";

		public Message to() {
			Message po = new Message();
			BeanUtils.copyProperties(this, po);
			return po;
		}

		public void from(Message po) {
			BeanUtils.copyProperties(po, this);
		}
	}
}
